package cn.vconinfo.lims.delivery.task;

import cn.vconinfo.base.oss.FileUtils;
import cn.vconinfo.base.utils.DateUtil;
import cn.vconinfo.base.utils.NumberUtil;
import cn.vconinfo.base.utils.StringUtils;
import cn.vconinfo.lims.delivery.entity.*;
import cn.vconinfo.lims.delivery.model.SpecimenRegister;
import cn.vconinfo.lims.delivery.model.SpecimenRegisterResult;
import cn.vconinfo.lims.delivery.model.WTestitemRelate;
import cn.vconinfo.lims.delivery.model.XiCangRequestInfo;
import cn.vconinfo.lims.delivery.service.InspectAppService;
import cn.vconinfo.lims.delivery.service.RequestTestItemService;
import cn.vconinfo.lims.delivery.service.TestItemSynchroService;
import cn.vconinfo.lims.delivery.service.XiCangInspectService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.AttributesImpl;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Result;
import javax.xml.transform.Transformer;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.sax.TransformerHandler;
import javax.xml.transform.stream.StreamResult;
import java.io.File;
import java.io.FileOutputStream;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class TestResultXmlExport {

    @Value("${lims.xmlStorePath}")
    private String xmlPath;

    @Value("${lims.imgStorePath}")
    private String imagePath;

    private final XiCangInspectService xiCangInspectService;
    private final TestItemSynchroService testItemSynchroService;
    private final RequestTestItemService requestTestItemService;
    private final InspectAppService inspectAppService;

    public boolean generateXml(List<SpecimenRegister> registerList){
        boolean isHandler = false;
        for(SpecimenRegister register : registerList){
            XiCangRequestQuery query = new XiCangRequestQuery();
            query.setHospSampleID(register.getPlaceholderCode());
            List<XiCangRequestInfo> requestInfoList = xiCangInspectService.queryXiCangRequestInfo(query);
            for(XiCangRequestInfo requestInfo : requestInfoList){
                isHandler = createXml(requestInfo, register);
            }

        }

        return isHandler;
    }

    public boolean generateReportImage(List<SpecimenRegister> registerList){
        boolean isHandler = false;
        try{
            for(SpecimenRegister register : registerList){
                TableResponseDTO responseDTO = inspectAppService.getImage(register.getSpecimenExtraId());
                if(responseDTO.getList() != null){
                    List<ImageDTO> imageList = (List<ImageDTO>)responseDTO.getList();
                    for (ImageDTO imageDTO : imageList){
                        String localFile = imageDTO.getUrl().substring(imageDTO.getUrl().lastIndexOf("/") + 1);
                        FileUtils.downloadPicture(imageDTO.getUrl(), imagePath.concat(localFile));
                    }
                }
            }
            isHandler = true;
        }catch (Exception ex){
            log.error("图片生成报错", ex);
            isHandler = false;
        }

        return isHandler;
    }


//    /**
//     *   下载报告图片
//     *
//     * @param registerList
//     * @return
//     */
//    public boolean generateReportImage(XiCangSampleResultForm form){
//        boolean isHandler = false;
//        try{
//            SpecimenRegister register = form.getRegister();
//            List<ImageDTO> imageList = form.getImageList();
//            for (ImageDTO imageDTO : imageList){
//                String localFile = imageDTO.getUrl().substring(imageDTO.getUrl().lastIndexOf("/") + 1);
//                FileUtils.downloadPicture(imageDTO.getUrl(), imagePath.concat(localFile));
//            }
//            isHandler = true;
//        }catch (Exception ex){
//            log.error("下载图片出错", ex);
//            isHandler = false;
//        }
//
//        return isHandler;
//    }


    private void toXmlString(TransformerHandler handler, XiCangRequestInfo requestInfo, SpecimenRegister register) throws SAXException {
        SpecimenRegisterQuery query = new SpecimenRegisterQuery();
        query.setSpecimenExtraId(register.getSpecimenExtraId());
        query.setStatus(1);
        List<SpecimenRegisterResult> resultList = testItemSynchroService.querySpecimenRegisterResult(query);
        if(!CollectionUtils.isEmpty(resultList)){
            AttributesImpl attr = new AttributesImpl();
            List<Long> projectIdList = resultList.parallelStream().map(SpecimenRegisterResult::getProjectId).collect(Collectors.toList());
            // 获取检验子项目的对照
            TestSubItemQuery relate = new TestSubItemQuery();
            relate.setHospitalId(register.getHospitalId());
            relate.setProjectIdList(projectIdList);
            Map<Long, WTestitemRelate> itemMapping = requestTestItemService.getTestSubItemMapping(relate);
            Assert.isTrue(itemMapping != null && !itemMapping.isEmpty(), "实验项目的对应关系不存在");
            Map<Long, ProjectDTO> projectDTOMap = testItemSynchroService.getProjectMap(projectIdList);
            Assert.isTrue(projectDTOMap != null && !projectDTOMap.isEmpty(), "实验项目没有存在");
            Map<Long, CollectionDTO> collectionDTOMap = testItemSynchroService.getTestItemUnit();
            UserDTO specimenUser = testItemSynchroService.getSpecimenUser(register.getDocimasterId());
            UserDTO auditUser = testItemSynchroService.getSpecimenUser(register.getConfirmManId());
            for(SpecimenRegisterResult result : resultList){
                ProjectDTO projectDTO = projectDTOMap.get(result.getProjectId());
                attr.clear();
//                attr.addAttribute("", "", "id", "", book.getId());
                handler.startElement("", "", "Table", attr);

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "体检流水号", attr);
                handler.characters("#".concat(toString(requestInfo.getPatientNumber())).toCharArray(), 0, toString(requestInfo.getPatientNumber()).length());
                handler.endElement("", "", "体检流水号");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "患者姓名", attr);
                handler.characters(toString(requestInfo.getName()).toCharArray(), 0, toString(requestInfo.getName()).length());
                handler.endElement("", "", "患者姓名");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "体检编号", attr);
                handler.characters("#".concat(toString(requestInfo.getPatientID())).toCharArray(), 0, toString(requestInfo.getPatientID()).length());
                handler.endElement("", "", "体检编号");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "熙康检验条码", attr);
                handler.characters("#".concat(toString(requestInfo.getHospSampleID())).toCharArray(), 0, toString(requestInfo.getHospSampleID()).length());
                handler.endElement("", "", "熙康检验条码");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "处方流水号", attr);
                handler.characters(toString(requestInfo.getRequestID()).toCharArray(), 0, toString(requestInfo.getRequestID()).length());
                handler.endElement("", "", "处方流水号");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "熙康项目编码", attr);
                handler.characters(toString(requestInfo.getItemCode()).toCharArray(), 0, toString(requestInfo.getItemCode()).length());
                handler.endElement("", "", "熙康项目编码");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "机器编码", attr);
                handler.characters("NBFTYXJYSYS001".toCharArray(), 0, "NBFTYXJYSYS001".length());
                handler.endElement("", "", "机器编码");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "熙康检验小项编码", attr);
                handler.characters(toString(itemMapping.get(result.getProjectId()).getSubItemCode()).toCharArray(), 0,
                        toString(itemMapping.get(result.getProjectId()).getSubItemCode()).length());
                handler.endElement("", "", "熙康检验小项编码");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "熙康检验项目名称", attr);
                handler.characters(toString(itemMapping.get(result.getProjectId()).getSubItemName()).toCharArray(), 0,
                        toString(itemMapping.get(result.getProjectId()).getSubItemName()).length());
                handler.endElement("", "", "熙康检验项目名称");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "结果", attr);
                handler.characters(toString(result.getProjectValue()).toCharArray(), 0, toString(result.getProjectValue()).length());
                handler.endElement("", "", "结果");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "标志", attr);
                handler.characters(resultRemark(result.getProjectValue(), projectDTO).toCharArray(), 0, resultRemark(result.getProjectValue(), projectDTO).length());
                handler.endElement("", "", "标志");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "单位", attr);
                handler.characters(toString(collectionDTOMap.get(projectDTO.getProjectUnit()).getCollectionName()).toCharArray(), 0,
                        toString(collectionDTOMap.get(projectDTO.getProjectUnit()).getCollectionName()).length());
                handler.endElement("", "", "单位");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "最小值", attr);
                handler.characters(toString(projectDTO.getExampleMin()).toCharArray(), 0, toString(projectDTO.getExampleMin()).length());
                handler.endElement("", "", "最小值");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "最大值", attr);
                handler.characters(toString(projectDTO.getExampleMax()).toCharArray(), 0, toString(projectDTO.getExampleMax()).length());
                handler.endElement("", "", "最大值");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "打印顺序", attr);
                handler.characters(toString(projectDTO.getProjectId()).toCharArray(), 0, toString(projectDTO.getProjectId()).length());
                handler.endElement("", "", "打印顺序");

                // 体检流水号
                attr.clear();
                if(specimenUser != null){
                    handler.startElement("", "", "检验人", attr);
                    handler.characters(toString(specimenUser.getUserName()).toCharArray(), 0, toString(specimenUser.getUserName()).length());
                    handler.endElement("", "", "检验人");
                }

                // 体检流水号
                attr.clear();
                if(auditUser != null){
                    handler.startElement("", "", "审核人", attr);
                    handler.characters(toString(auditUser.getUserName()).toCharArray(), 0, toString(auditUser.getUserName()).length());
                    handler.endElement("", "", "审核人");
                }

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "审核时间", attr);
                handler.characters(toString(DateUtil.format(register.getReportTime(), DateUtil.YYYMMDDHHMMMSS)).toCharArray(), 0,
                        toString(DateUtil.format(register.getReportTime(), DateUtil.YYYMMDDHHMMMSS)).length());
                handler.endElement("", "", "审核时间");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "项目类型", attr);
                String itemType = "1";
                if(NumberUtil.isMoney(result.getProjectValue())){
                    itemType = "0";
                }
                handler.characters(itemType.toCharArray(), 0, itemType.length());
                handler.endElement("", "", "项目类型");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "流水号", attr);
                handler.characters(toString(register.getSpecimenExtraId()).toCharArray(), 0, toString(register.getSpecimenExtraId()).length());
                handler.endElement("", "", "流水号");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "参考范围", attr);
                handler.characters(toString(projectDTO.getExampleRange()).toCharArray(), 0, toString(projectDTO.getExampleRange()).length());
                handler.endElement("", "", "参考范围");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "检验单位", attr);
                handler.characters("宁波泛肽医学检验实验室".toCharArray(), 0, "宁波泛肽医学检验实验室".length());
                handler.endElement("", "", "检验单位");

                // 体检流水号
                attr.clear();
                handler.startElement("", "", "条码号", attr);
                handler.characters(toString(register.getDailyCode()).toCharArray(), 0, toString(register.getDailyCode()).length());
                handler.endElement("", "", "条码号");


                handler.endElement("", "", "Table");
            }
        }
    }

    private boolean createXml(XiCangRequestInfo requestInfo, SpecimenRegister register){
        boolean isHandler = false;
        // 1、创建一个SAXTransformerFactory类的对象
        SAXTransformerFactory tff = (SAXTransformerFactory) SAXTransformerFactory.newInstance();

        String xmlFile = "CG".concat(DateUtil.getCurrentDateStr(DateUtil.YYYYMMDDHHMMSS)).concat(".xml");
        // 5、创建一个Result对象
        File fObj = new File(xmlPath, xmlFile);
        try {
            // 2、通过SAXTransformerFactory创建一个TransformerHandler的对象
            TransformerHandler handler = tff.newTransformerHandler();
            // 3、通过handler创建一个Transformer对象
            Transformer tr = handler.getTransformer();
            // 4、通过Transformer对象对生成的xml文件进行设置
            // 设置编码方式
            tr.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
            // 设置是否换行
            tr.setOutputProperty(OutputKeys.INDENT, "yes");
            // 判断文件是否存在
            if(!fObj.exists()){
                fObj.createNewFile();
            }
            Result result = new StreamResult(new FileOutputStream(fObj));
            // 6、使RESULT与handler关联
            handler.setResult(result);

            // 打开document
            handler.startDocument();
            AttributesImpl attr = new AttributesImpl();
            handler.startElement("", "", "ResultsDataSet", attr);
            attr.clear();

            // xml明细数据
            toXmlString(handler, requestInfo, register);

            handler.endElement("", "", "ResultsDataSet");
            // 关闭document
            handler.endDocument();
            log.info("生成{}成功", xmlFile);
            isHandler =true;
        } catch (Exception e) {
            log.info("生成{}失败", xmlFile, e);
            isHandler = false;
            fObj.delete();
        }

        return isHandler;
    }

    private String toString(Object value){
        return StringUtils.null2Str(value);
    }

    private String resultRemark(String testResult, ProjectDTO projectDTO){
        String remark = "";
        if(NumberUtil.isMoney(testResult)){
            if(projectDTO.getDangerMin() != null && NumberUtil.compareCalcuMark(testResult, StringUtils.null2Str(projectDTO.getDangerMin()), "<")){
                remark = "低于极限";
            }else if(projectDTO.getDangerMax() != null && NumberUtil.compareCalcuMark(testResult, StringUtils.null2Str(projectDTO.getDangerMax()), ">")){
                remark = "高于极限";
            }else if(projectDTO.getExampleMin() != null && NumberUtil.compareCalcuMark(testResult, StringUtils.null2Str(projectDTO.getExampleMin()), "<")){
                remark = "低";
            }else if(projectDTO.getExampleMax() != null && NumberUtil.compareCalcuMark(testResult, StringUtils.null2Str(projectDTO.getExampleMax()), ">")){
                remark = "高";
            }
        }else{
            remark = testResult;
        }

        return remark;
    }

}
